{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "_cell_guid": "b1076dfc-b9ad-4769-8c92-a6c4dae69d19",
    "_kg_hide-input": true,
    "_kg_hide-output": true,
    "_uuid": "8f2839f25d086af736a60e9eeb907d3b93b6e0e5",
    "execution": {
     "iopub.execute_input": "2024-05-09T06:15:56.563354Z",
     "iopub.status.busy": "2024-05-09T06:15:56.562173Z",
     "iopub.status.idle": "2024-05-09T06:15:56.595477Z",
     "shell.execute_reply": "2024-05-09T06:15:56.593063Z",
     "shell.execute_reply.started": "2024-05-09T05:52:20.910039Z"
    },
    "papermill": {
     "duration": 0.071757,
     "end_time": "2024-05-09T06:15:56.595852",
     "exception": true,
     "start_time": "2024-05-09T06:15:56.524095",
     "status": "failed"
    },
    "tags": []
   },
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'os' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-1-89f4f4946d4e>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      2\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mpandas\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mpd\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      3\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0;32mfor\u001b[0m \u001b[0mdirname\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfilenames\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwalk\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'/data/nlplstm'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      5\u001b[0m     \u001b[0;32mfor\u001b[0m \u001b[0mfilename\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mfilenames\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      6\u001b[0m         \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdirname\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfilename\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mNameError\u001b[0m: name 'os' is not defined"
     ]
    }
   ],
   "source": [
    "\n",
    "\n",
    "import numpy as np \n",
    "import pandas as pd \n",
    "\n",
    "for dirname, _, filenames in os.walk('/data/nlplstm'):\n",
    "    for filename in filenames:\n",
    "        print(os.path.join(dirname, filename))\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "_kg_hide-input": true,
    "execution": {
     "iopub.execute_input": "2024-05-09T05:52:24.337479Z",
     "iopub.status.busy": "2024-05-09T05:52:24.336974Z",
     "iopub.status.idle": "2024-05-09T05:52:35.947073Z",
     "shell.execute_reply": "2024-05-09T05:52:35.945433Z",
     "shell.execute_reply.started": "2024-05-09T05:52:24.337436Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "import re\n",
    "import string\n",
    "import numpy as np \n",
    "import random\n",
    "import pandas as pd \n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "%matplotlib inline\n",
    "from plotly import graph_objs as go\n",
    "import plotly.express as px\n",
    "import plotly.figure_factory as ff\n",
    "from collections import Counter\n",
    "\n",
    "from PIL import Image\n",
    "from wordcloud import WordCloud, STOPWORDS, ImageColorGenerator\n",
    "\n",
    "\n",
    "import nltk\n",
    "from nltk.corpus import stopwords\n",
    "from nltk.tokenize import word_tokenize\n",
    "\n",
    "from tqdm import tqdm\n",
    "import os\n",
    "import nltk\n",
    "import spacy\n",
    "import random\n",
    "from spacy.util import compounding\n",
    "from spacy.util import minibatch\n",
    "\n",
    "from collections import defaultdict\n",
    "from collections import Counter\n",
    "\n",
    "import keras\n",
    "from keras.models import Sequential\n",
    "from keras.initializers import Constant\n",
    "from keras.layers import (LSTM, \n",
    "                          Embedding, \n",
    "                          BatchNormalization,\n",
    "                          Dense, \n",
    "                          TimeDistributed, \n",
    "                          Dropout, \n",
    "                          Bidirectional,\n",
    "                          Flatten, \n",
    "                          GlobalMaxPool1D)\n",
    "from keras.preprocessing.text import Tokenizer\n",
    "from keras.preprocessing.sequence import pad_sequences\n",
    "from keras.layers.embeddings import Embedding\n",
    "from keras.callbacks import ModelCheckpoint, ReduceLROnPlateau\n",
    "from keras.optimizers import Adam\n",
    "\n",
    "from sklearn.metrics import (\n",
    "    precision_score, \n",
    "    recall_score, \n",
    "    f1_score, \n",
    "    classification_report,\n",
    "    accuracy_score\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "_kg_hide-input": true,
    "execution": {
     "iopub.execute_input": "2024-05-09T05:53:25.782312Z",
     "iopub.status.busy": "2024-05-09T05:53:25.781809Z",
     "iopub.status.idle": "2024-05-09T05:53:25.796556Z",
     "shell.execute_reply": "2024-05-09T05:53:25.795079Z",
     "shell.execute_reply.started": "2024-05-09T05:53:25.782268Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# 定义所有调色板的颜色。\n",
    "primary_blue = \"#496595\"\n",
    "primary_blue2 = \"#85a1c1\"\n",
    "primary_blue3 = \"#3f4d63\"\n",
    "primary_grey = \"#c6ccd8\"\n",
    "primary_black = \"#202022\"\n",
    "primary_bgcolor = \"#f4f0ea\"\n",
    "\n",
    "primary_green = px.colors.qualitative.Plotly[2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-09T05:53:29.835258Z",
     "iopub.status.busy": "2024-05-09T05:53:29.834719Z",
     "iopub.status.idle": "2024-05-09T05:53:29.998612Z",
     "shell.execute_reply": "2024-05-09T05:53:29.997620Z",
     "shell.execute_reply.started": "2024-05-09T05:53:29.835218Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "df = pd.read_csv(\"/kaggle/input/sms-spam-collection-dataset/spam.csv\", encoding=\"latin-1\")\n",
    "\n",
    "df = df.dropna(how=\"any\", axis=1)\n",
    "df.columns = ['target', 'message']\n",
    "\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-09T05:53:42.798658Z",
     "iopub.status.busy": "2024-05-09T05:53:42.797962Z",
     "iopub.status.idle": "2024-05-09T05:53:42.825357Z",
     "shell.execute_reply": "2024-05-09T05:53:42.824429Z",
     "shell.execute_reply.started": "2024-05-09T05:53:42.798613Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "df['message_len'] = df['message'].apply(lambda x: len(x.split(' ')))\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-09T05:53:45.587995Z",
     "iopub.status.busy": "2024-05-09T05:53:45.587395Z",
     "iopub.status.idle": "2024-05-09T05:53:45.600514Z",
     "shell.execute_reply": "2024-05-09T05:53:45.599147Z",
     "shell.execute_reply.started": "2024-05-09T05:53:45.587955Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "max(df['message_len'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-09T05:53:50.354817Z",
     "iopub.status.busy": "2024-05-09T05:53:50.354303Z",
     "iopub.status.idle": "2024-05-09T05:53:50.369793Z",
     "shell.execute_reply": "2024-05-09T05:53:50.368571Z",
     "shell.execute_reply.started": "2024-05-09T05:53:50.354775Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "balance_counts = df.groupby('target')['target'].agg('count').values\n",
    "balance_counts"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "_kg_hide-input": true,
    "execution": {
     "iopub.execute_input": "2024-05-09T05:53:52.794650Z",
     "iopub.status.busy": "2024-05-09T05:53:52.794231Z",
     "iopub.status.idle": "2024-05-09T05:53:52.921564Z",
     "shell.execute_reply": "2024-05-09T05:53:52.920411Z",
     "shell.execute_reply.started": "2024-05-09T05:53:52.794614Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "fig = go.Figure()\n",
    "fig.add_trace(go.Bar(\n",
    "    x=['ham'],\n",
    "    y=[balance_counts[0]],\n",
    "    name='ham',\n",
    "    text=[balance_counts[0]],\n",
    "    textposition='auto',\n",
    "    marker_color=primary_blue\n",
    "))\n",
    "fig.add_trace(go.Bar(\n",
    "    x=['spam'],\n",
    "    y=[balance_counts[1]],\n",
    "    name='spam',\n",
    "    text=[balance_counts[1]],\n",
    "    textposition='auto',\n",
    "    marker_color=primary_grey\n",
    "))\n",
    "fig.update_layout(\n",
    "    title='<span style=\"font-size:32px; font-family:Times New Roman\">Dataset distribution by target</span>'\n",
    ")\n",
    "fig.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "_kg_hide-input": true,
    "execution": {
     "iopub.execute_input": "2024-05-09T05:54:01.132225Z",
     "iopub.status.busy": "2024-05-09T05:54:01.131760Z",
     "iopub.status.idle": "2024-05-09T05:54:01.197974Z",
     "shell.execute_reply": "2024-05-09T05:54:01.196760Z",
     "shell.execute_reply.started": "2024-05-09T05:54:01.132189Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "ham_df = df[df['target'] == 'ham']['message_len'].value_counts().sort_index()\n",
    "spam_df = df[df['target'] == 'spam']['message_len'].value_counts().sort_index()\n",
    "\n",
    "fig = go.Figure()\n",
    "fig.add_trace(go.Scatter(\n",
    "    x=ham_df.index,\n",
    "    y=ham_df.values,\n",
    "    name='ham',\n",
    "    fill='tozeroy',\n",
    "    marker_color=primary_blue,\n",
    "))\n",
    "fig.add_trace(go.Scatter(\n",
    "    x=spam_df.index,\n",
    "    y=spam_df.values,\n",
    "    name='spam',\n",
    "    fill='tozeroy',\n",
    "    marker_color=primary_grey,\n",
    "))\n",
    "fig.update_layout(\n",
    "    title='<span style=\"font-size:32px; font-family:Times New Roman\">Data Roles in Different Fields</span>'\n",
    ")\n",
    "fig.update_xaxes(range=[0, 70])\n",
    "fig.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-09T05:54:16.955859Z",
     "iopub.status.busy": "2024-05-09T05:54:16.955426Z",
     "iopub.status.idle": "2024-05-09T05:54:16.963781Z",
     "shell.execute_reply": "2024-05-09T05:54:16.962509Z",
     "shell.execute_reply.started": "2024-05-09T05:54:16.955825Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# Special thanks to https://www.kaggle.com/tanulsingh077 for this function\n",
    "def clean_text(text):\n",
    "    '''使文本小写，删除方括号中的文本，删除链接，删除标点符号并删除包含数字的单词。'''\n",
    "    text = str(text).lower()\n",
    "    text = re.sub('\\[.*?\\]', '', text)\n",
    "    text = re.sub('https?://\\S+|www\\.\\S+', '', text)\n",
    "    text = re.sub('<.*?>+', '', text)\n",
    "    text = re.sub('[%s]' % re.escape(string.punctuation), '', text)\n",
    "    text = re.sub('\\n', '', text)\n",
    "    text = re.sub('\\w*\\d\\w*', '', text)\n",
    "    return text"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "_kg_hide-output": false,
    "execution": {
     "iopub.execute_input": "2024-05-09T05:54:19.579199Z",
     "iopub.status.busy": "2024-05-09T05:54:19.578728Z",
     "iopub.status.idle": "2024-05-09T05:54:19.802187Z",
     "shell.execute_reply": "2024-05-09T05:54:19.800790Z",
     "shell.execute_reply.started": "2024-05-09T05:54:19.579154Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "df['message_clean'] = df['message'].apply(clean_text)\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "_kg_hide-output": true,
    "execution": {
     "iopub.execute_input": "2024-05-09T05:54:24.284258Z",
     "iopub.status.busy": "2024-05-09T05:54:24.283593Z",
     "iopub.status.idle": "2024-05-09T05:54:24.576822Z",
     "shell.execute_reply": "2024-05-09T05:54:24.575441Z",
     "shell.execute_reply.started": "2024-05-09T05:54:24.284205Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "stop_words = stopwords.words('english')\n",
    "more_stopwords = ['u', 'im', 'c']\n",
    "stop_words = stop_words + more_stopwords\n",
    "\n",
    "def remove_stopwords(text):\n",
    "    text = ' '.join(word for word in text.split(' ') if word not in stop_words)\n",
    "    return text\n",
    "    \n",
    "df['message_clean'] = df['message_clean'].apply(remove_stopwords)\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-09T05:54:32.451046Z",
     "iopub.status.busy": "2024-05-09T05:54:32.450123Z",
     "iopub.status.idle": "2024-05-09T05:54:32.457065Z",
     "shell.execute_reply": "2024-05-09T05:54:32.455546Z",
     "shell.execute_reply.started": "2024-05-09T05:54:32.450984Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "stemmer = nltk.SnowballStemmer(\"english\")\n",
    "\n",
    "def stemm_text(text):\n",
    "    text = ' '.join(stemmer.stem(word) for word in text.split(' '))\n",
    "    return text"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "_kg_hide-output": true,
    "execution": {
     "iopub.execute_input": "2024-05-09T05:54:36.419750Z",
     "iopub.status.busy": "2024-05-09T05:54:36.419261Z",
     "iopub.status.idle": "2024-05-09T05:54:37.745687Z",
     "shell.execute_reply": "2024-05-09T05:54:37.742967Z",
     "shell.execute_reply.started": "2024-05-09T05:54:36.419710Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "df['message_clean'] = df['message_clean'].apply(stemm_text)\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-09T05:54:44.300356Z",
     "iopub.status.busy": "2024-05-09T05:54:44.299843Z",
     "iopub.status.idle": "2024-05-09T05:54:44.308720Z",
     "shell.execute_reply": "2024-05-09T05:54:44.306646Z",
     "shell.execute_reply.started": "2024-05-09T05:54:44.300304Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "def preprocess_data(text):\n",
    "    # 干净的标点符号、url等等\n",
    "    text = clean_text(text)\n",
    "    # 删除stopwords\n",
    "    text = ' '.join(word for word in text.split(' ') if word not in stop_words)\n",
    "    # 把这个句子里的所有单词都记下来\n",
    "    text = ' '.join(stemmer.stem(word) for word in text.split(' '))\n",
    "    \n",
    "    return text"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-09T05:54:47.116268Z",
     "iopub.status.busy": "2024-05-09T05:54:47.115750Z",
     "iopub.status.idle": "2024-05-09T05:54:48.556913Z",
     "shell.execute_reply": "2024-05-09T05:54:48.555043Z",
     "shell.execute_reply.started": "2024-05-09T05:54:47.116228Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "df['message_clean'] = df['message_clean'].apply(preprocess_data)\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "_kg_hide-output": true,
    "execution": {
     "iopub.execute_input": "2024-05-09T05:54:51.924130Z",
     "iopub.status.busy": "2024-05-09T05:54:51.923663Z",
     "iopub.status.idle": "2024-05-09T05:54:51.946505Z",
     "shell.execute_reply": "2024-05-09T05:54:51.944772Z",
     "shell.execute_reply.started": "2024-05-09T05:54:51.924089Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from sklearn.preprocessing import LabelEncoder\n",
    "\n",
    "le = LabelEncoder()\n",
    "le.fit(df['target'])\n",
    "\n",
    "df['target_encoded'] = le.transform(df['target'])\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "_kg_hide-input": true,
    "execution": {
     "iopub.execute_input": "2024-05-09T05:54:55.052133Z",
     "iopub.status.busy": "2024-05-09T05:54:55.051645Z",
     "iopub.status.idle": "2024-05-09T05:54:56.551806Z",
     "shell.execute_reply": "2024-05-09T05:54:56.550215Z",
     "shell.execute_reply.started": "2024-05-09T05:54:55.052093Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "twitter_mask = np.array(Image.open('/kaggle/input/masksforwordclouds/twitter_mask3.jpg'))\n",
    "\n",
    "wc = WordCloud(\n",
    "    background_color='white', \n",
    "    max_words=200, \n",
    "    mask=twitter_mask,\n",
    ")\n",
    "wc.generate(' '.join(text for text in df.loc[df['target'] == 'ham', 'message_clean']))\n",
    "plt.figure(figsize=(18,10))\n",
    "plt.title('Top words for HAM messages', \n",
    "          fontdict={'size': 22,  'verticalalignment': 'bottom'})\n",
    "plt.imshow(wc)\n",
    "plt.axis(\"off\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "_kg_hide-input": true,
    "execution": {
     "iopub.execute_input": "2024-05-09T05:54:57.364081Z",
     "iopub.status.busy": "2024-05-09T05:54:57.363221Z",
     "iopub.status.idle": "2024-05-09T05:54:58.378859Z",
     "shell.execute_reply": "2024-05-09T05:54:58.377537Z",
     "shell.execute_reply.started": "2024-05-09T05:54:57.364032Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "twitter_mask = np.array(Image.open('/kaggle/input/masksforwordclouds/twitter_mask3.jpg'))\n",
    "\n",
    "wc = WordCloud(\n",
    "    background_color='white', \n",
    "    max_words=200, \n",
    "    mask=twitter_mask,\n",
    ")\n",
    "wc.generate(' '.join(text for text in df.loc[df['target'] == 'spam', 'message_clean']))\n",
    "plt.figure(figsize=(18,10))\n",
    "plt.title('Top words for SPAM messages', \n",
    "          fontdict={'size': 22,  'verticalalignment': 'bottom'})\n",
    "plt.imshow(wc)\n",
    "plt.axis(\"off\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-09T05:55:18.973291Z",
     "iopub.status.busy": "2024-05-09T05:55:18.972788Z",
     "iopub.status.idle": "2024-05-09T05:55:18.980361Z",
     "shell.execute_reply": "2024-05-09T05:55:18.979338Z",
     "shell.execute_reply.started": "2024-05-09T05:55:18.973248Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# 如何定义X和y(从短信数据)使用COUNTVECTORIZER\n",
    "x = df['message_clean']\n",
    "y = df['target_encoded']\n",
    "\n",
    "print(len(x), len(y))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-09T05:55:22.012861Z",
     "iopub.status.busy": "2024-05-09T05:55:22.012397Z",
     "iopub.status.idle": "2024-05-09T05:55:22.026022Z",
     "shell.execute_reply": "2024-05-09T05:55:22.024551Z",
     "shell.execute_reply.started": "2024-05-09T05:55:22.012819Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# 分为训练集和测试集\n",
    "from sklearn.model_selection import train_test_split\n",
    "\n",
    "x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=42)\n",
    "print(len(x_train), len(y_train))\n",
    "print(len(x_test), len(y_test))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-09T05:55:24.142227Z",
     "iopub.status.busy": "2024-05-09T05:55:24.141658Z",
     "iopub.status.idle": "2024-05-09T05:55:24.247503Z",
     "shell.execute_reply": "2024-05-09T05:55:24.246177Z",
     "shell.execute_reply.started": "2024-05-09T05:55:24.142178Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from sklearn.feature_extraction.text import CountVectorizer\n",
    "\n",
    "# 实例化向量\n",
    "vect = CountVectorizer()\n",
    "vect.fit(x_train)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-09T05:55:29.053044Z",
     "iopub.status.busy": "2024-05-09T05:55:29.052187Z",
     "iopub.status.idle": "2024-05-09T05:55:29.153589Z",
     "shell.execute_reply": "2024-05-09T05:55:29.151583Z",
     "shell.execute_reply.started": "2024-05-09T05:55:29.052955Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# 使用训练集从训练集和测试集创建文档术语矩阵\n",
    "x_train_dtm = vect.transform(x_train)\n",
    "x_test_dtm = vect.transform(x_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-09T05:55:34.341952Z",
     "iopub.status.busy": "2024-05-09T05:55:34.341483Z",
     "iopub.status.idle": "2024-05-09T05:55:34.348423Z",
     "shell.execute_reply": "2024-05-09T05:55:34.347031Z",
     "shell.execute_reply.started": "2024-05-09T05:55:34.341912Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "vect_tunned = CountVectorizer(stop_words='english', ngram_range=(1,2), min_df=0.1, max_df=0.7, max_features=100)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "_kg_hide-output": true,
    "execution": {
     "iopub.execute_input": "2024-05-09T05:55:38.772823Z",
     "iopub.status.busy": "2024-05-09T05:55:38.772335Z",
     "iopub.status.idle": "2024-05-09T05:55:38.795476Z",
     "shell.execute_reply": "2024-05-09T05:55:38.793878Z",
     "shell.execute_reply.started": "2024-05-09T05:55:38.772785Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from sklearn.feature_extraction.text import TfidfTransformer\n",
    "\n",
    "tfidf_transformer = TfidfTransformer()\n",
    "\n",
    "tfidf_transformer.fit(x_train_dtm)\n",
    "x_train_tfidf = tfidf_transformer.transform(x_train_dtm)\n",
    "\n",
    "x_train_tfidf"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-09T05:55:42.765234Z",
     "iopub.status.busy": "2024-05-09T05:55:42.764732Z",
     "iopub.status.idle": "2024-05-09T05:55:42.770779Z",
     "shell.execute_reply": "2024-05-09T05:55:42.769147Z",
     "shell.execute_reply.started": "2024-05-09T05:55:42.765191Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "texts = df['message_clean']\n",
    "target = df['target_encoded']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-09T05:55:45.940932Z",
     "iopub.status.busy": "2024-05-09T05:55:45.940511Z",
     "iopub.status.idle": "2024-05-09T05:55:46.072812Z",
     "shell.execute_reply": "2024-05-09T05:55:46.071554Z",
     "shell.execute_reply.started": "2024-05-09T05:55:45.940895Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# 计算词汇的长度\n",
    "word_tokenizer = Tokenizer()\n",
    "word_tokenizer.fit_on_texts(texts)\n",
    "\n",
    "vocab_length = len(word_tokenizer.word_index) + 1\n",
    "vocab_length"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "source": [
    "### Pad_sequences\n",
    "\n",
    "https://www.tensorflow.org/api_docs/python/tf/keras/preprocessing/sequence/pad_sequences\n",
    "\n",
    "```python\n",
    "tf.keras.preprocessing.sequence.pad_sequences(\n",
    "    sequences, maxlen=None, dtype='int32', padding='pre',\n",
    "    truncating='pre', value=0.0\n",
    ")\n",
    "```\n",
    "\n",
    "这个函数将序列(整数列表)的列表(长度为num_samples)转换为形状为(num_samples, num_timesteps)的2D Numpy数组。Num_timesteps可以是maxlen参数(如果提供的话)，也可以是列表中最长序列的长度。\n",
    "\n",
    "```python\n",
    ">>> sequence = [[1], [2, 3], [4, 5, 6]]\n",
    ">>> tf.keras.preprocessing.sequence.pad_sequences(sequence, padding='post')\n",
    "array([[1, 0, 0],\n",
    "       [2, 3, 0],\n",
    "       [4, 5, 6]], dtype=int32)\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "_kg_hide-output": true,
    "execution": {
     "iopub.execute_input": "2024-05-09T05:55:49.412774Z",
     "iopub.status.busy": "2024-05-09T05:55:49.412362Z",
     "iopub.status.idle": "2024-05-09T05:55:50.514825Z",
     "shell.execute_reply": "2024-05-09T05:55:50.513830Z",
     "shell.execute_reply.started": "2024-05-09T05:55:49.412732Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "def embed(corpus): \n",
    "    return word_tokenizer.texts_to_sequences(corpus)\n",
    "\n",
    "longest_train = max(texts, key=lambda sentence: len(word_tokenize(sentence)))\n",
    "length_long_sentence = len(word_tokenize(longest_train))\n",
    "\n",
    "train_padded_sentences = pad_sequences(\n",
    "    embed(texts), \n",
    "    length_long_sentence, \n",
    "    padding='post'\n",
    ")\n",
    "\n",
    "train_padded_sentences"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "source": [
    "### GloVe\n",
    "\n",
    "GloVe 方法建立在一个重要的理念之上，\n",
    "\n",
    "> 您可以从共现矩阵中导出单词之间的语义关系。\n",
    "\n",
    "为了获得单词的向量表示，我们可以使用一种称为GloVe (Global Vectors for Word representation)的无监督学习算法，该算法专注于整个语料库中的单词共现。它的嵌入与两个单词同时出现的概率有关。\n",
    "\n",
    "词嵌入基本上是一种词表示形式，它将人类对语言的理解与机器的理解联系起来。他们已经学会了在n维空间中对文本的表示，在n维空间中，具有相同含义的单词具有相似的表示。意思是两个相似的单词由几乎相似的向量表示，这些向量非常紧密地放在向量空间中。\n",
    "\n",
    "因此，当使用词嵌入时，所有单独的词都被表示为预定义向量空间中的实值向量。每个单词被映射到一个向量，向量值以一种类似于神经网络的方式学习。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-09T05:55:55.805150Z",
     "iopub.status.busy": "2024-05-09T05:55:55.804665Z",
     "iopub.status.idle": "2024-05-09T05:56:21.066546Z",
     "shell.execute_reply": "2024-05-09T05:56:21.050868Z",
     "shell.execute_reply.started": "2024-05-09T05:55:55.805110Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "embeddings_dictionary = dict()\n",
    "embedding_dim = 100\n",
    "\n",
    "# Load GloVe 100D embeddings\n",
    "with open('/kaggle/input/glove6b100dtxt/glove.6B.100d.txt') as fp:\n",
    "    for line in fp.readlines():\n",
    "        records = line.split()\n",
    "        word = records[0]\n",
    "        vector_dimensions = np.asarray(records[1:], dtype='float32')\n",
    "        embeddings_dictionary [word] = vector_dimensions\n",
    "\n",
    "# embeddings_dictionary"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "_kg_hide-output": true,
    "execution": {
     "iopub.execute_input": "2024-05-09T05:56:45.286299Z",
     "iopub.status.busy": "2024-05-09T05:56:45.285807Z",
     "iopub.status.idle": "2024-05-09T05:56:45.317564Z",
     "shell.execute_reply": "2024-05-09T05:56:45.316311Z",
     "shell.execute_reply.started": "2024-05-09T05:56:45.286257Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# 现在我们将加载那些出现在Glove字典中的单词的嵌入向量。其他将初始化为0。\n",
    "\n",
    "embedding_matrix = np.zeros((vocab_length, embedding_dim))\n",
    "\n",
    "for word, index in word_tokenizer.word_index.items():\n",
    "    embedding_vector = embeddings_dictionary.get(word)\n",
    "    if embedding_vector is not None:\n",
    "        embedding_matrix[index] = embedding_vector\n",
    "        \n",
    "embedding_matrix"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "_kg_hide-input": true,
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "import plotly.figure_factory as ff\n",
    "\n",
    "x_axes = ['Ham', 'Spam']\n",
    "y_axes =  ['Spam', 'Ham']\n",
    "\n",
    "def conf_matrix(z, x=x_axes, y=y_axes):\n",
    "    \n",
    "    z = np.flip(z, 0)\n",
    "\n",
    "    # 将z的每个元素更改为注释的字符串类型\n",
    "    z_text = [[str(y) for y in x] for x in z]\n",
    "\n",
    "    # 设置图\n",
    "    fig = ff.create_annotated_heatmap(z, x=x, y=y, annotation_text=z_text, colorscale='Viridis')\n",
    "\n",
    "    # 增加标题\n",
    "    fig.update_layout(title_text='<b>Confusion matrix</b>',\n",
    "                      xaxis = dict(title='Predicted value'),\n",
    "                      yaxis = dict(title='Real value')\n",
    "                     )\n",
    "\n",
    "    # 添加colorbar\n",
    "    fig['data'][0]['showscale'] = True\n",
    "    \n",
    "    return fig"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# Create a Multinomial Naive Bayes model\n",
    "from sklearn.naive_bayes import MultinomialNB\n",
    "nb = MultinomialNB()\n",
    "\n",
    "# Train the model\n",
    "nb.fit(x_train_dtm, y_train)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-09T05:56:54.013893Z",
     "iopub.status.busy": "2024-05-09T05:56:54.013461Z",
     "iopub.status.idle": "2024-05-09T05:56:54.021849Z",
     "shell.execute_reply": "2024-05-09T05:56:54.019980Z",
     "shell.execute_reply.started": "2024-05-09T05:56:54.013857Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# 将数据分成训练集和测试集\n",
    "X_train, X_test, y_train, y_test = train_test_split(\n",
    "    train_padded_sentences, \n",
    "    target, \n",
    "    test_size=0.25\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-09T05:56:56.686247Z",
     "iopub.status.busy": "2024-05-09T05:56:56.685829Z",
     "iopub.status.idle": "2024-05-09T05:56:57.191740Z",
     "shell.execute_reply": "2024-05-09T05:56:57.190307Z",
     "shell.execute_reply.started": "2024-05-09T05:56:56.686213Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# Model from https://www.kaggle.com/mariapushkareva/nlp-disaster-tweets-with-glove-and-lstm/data\n",
    "\n",
    "def glove_lstm():\n",
    "    model = Sequential()\n",
    "    \n",
    "    model.add(Embedding(\n",
    "        input_dim=embedding_matrix.shape[0], \n",
    "        output_dim=embedding_matrix.shape[1], \n",
    "        weights = [embedding_matrix], \n",
    "        input_length=length_long_sentence\n",
    "    ))\n",
    "    \n",
    "    model.add(Bidirectional(LSTM(\n",
    "        length_long_sentence, \n",
    "        return_sequences = True, \n",
    "        recurrent_dropout=0.2\n",
    "    )))\n",
    "    \n",
    "    model.add(GlobalMaxPool1D())\n",
    "    model.add(BatchNormalization())\n",
    "    model.add(Dropout(0.5))\n",
    "    model.add(Dense(length_long_sentence, activation = \"relu\"))\n",
    "    model.add(Dropout(0.5))\n",
    "    model.add(Dense(length_long_sentence, activation = \"relu\"))\n",
    "    model.add(Dropout(0.5))\n",
    "    model.add(Dense(1, activation = 'sigmoid'))\n",
    "    model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['accuracy'])\n",
    "    \n",
    "    return model\n",
    "\n",
    "model = glove_lstm()\n",
    "model.summary()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "_kg_hide-output": true,
    "execution": {
     "iopub.execute_input": "2024-05-09T05:57:03.510340Z",
     "iopub.status.busy": "2024-05-09T05:57:03.509909Z",
     "iopub.status.idle": "2024-05-09T05:59:26.242143Z",
     "shell.execute_reply": "2024-05-09T05:59:26.241013Z",
     "shell.execute_reply.started": "2024-05-09T05:57:03.510304Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# Load the model and train!!\n",
    "\n",
    "model = glove_lstm()\n",
    "\n",
    "checkpoint = ModelCheckpoint(\n",
    "    'model.h5', \n",
    "    monitor = 'val_loss', \n",
    "    verbose = 1, \n",
    "    save_best_only = True\n",
    ")\n",
    "reduce_lr = ReduceLROnPlateau(\n",
    "    monitor = 'val_loss', \n",
    "    factor = 0.2, \n",
    "    verbose = 1, \n",
    "    patience = 5,                        \n",
    "    min_lr = 0.001\n",
    ")\n",
    "history = model.fit(\n",
    "    X_train, \n",
    "    y_train, \n",
    "    epochs = 7,\n",
    "    batch_size = 32,\n",
    "    validation_data = (X_test, y_test),\n",
    "    verbose = 1,\n",
    "    callbacks = [reduce_lr, checkpoint]\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "_kg_hide-input": true,
    "execution": {
     "iopub.execute_input": "2024-05-09T06:00:08.154538Z",
     "iopub.status.busy": "2024-05-09T06:00:08.153950Z",
     "iopub.status.idle": "2024-05-09T06:00:08.168257Z",
     "shell.execute_reply": "2024-05-09T06:00:08.166885Z",
     "shell.execute_reply.started": "2024-05-09T06:00:08.154488Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "def plot_learning_curves(history, arr):\n",
    "    fig, ax = plt.subplots(1, 2, figsize=(20, 5))\n",
    "    for idx in range(2):\n",
    "        ax[idx].plot(history.history[arr[idx][0]])\n",
    "        ax[idx].plot(history.history[arr[idx][1]])\n",
    "        ax[idx].legend([arr[idx][0], arr[idx][1]],fontsize=18)\n",
    "        ax[idx].set_xlabel('A ',fontsize=16)\n",
    "        ax[idx].set_ylabel('B',fontsize=16)\n",
    "        ax[idx].set_title(arr[idx][0] + ' X ' + arr[idx][1],fontsize=16)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-09T06:00:11.402717Z",
     "iopub.status.busy": "2024-05-09T06:00:11.402287Z",
     "iopub.status.idle": "2024-05-09T06:00:11.852245Z",
     "shell.execute_reply": "2024-05-09T06:00:11.850857Z",
     "shell.execute_reply.started": "2024-05-09T06:00:11.402679Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "plot_learning_curves(history, [['loss', 'val_loss'],['accuracy', 'val_accuracy']])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-09T06:00:15.481523Z",
     "iopub.status.busy": "2024-05-09T06:00:15.481092Z",
     "iopub.status.idle": "2024-05-09T06:00:17.104884Z",
     "shell.execute_reply": "2024-05-09T06:00:17.102977Z",
     "shell.execute_reply.started": "2024-05-09T06:00:15.481485Z"
    },
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "y_preds = (model.predict(X_test) > 0.5).astype(\"int32\")\n",
    "conf_matrix(metrics.confusion_matrix(y_test, y_preds))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "papermill": {
     "duration": null,
     "end_time": null,
     "exception": null,
     "start_time": null,
     "status": "pending"
    },
    "tags": []
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kaggle": {
   "accelerator": "none",
   "dataSources": [
    {
     "databundleVersionId": 869809,
     "sourceId": 17777,
     "sourceType": "competition"
    },
    {
     "datasetId": 483,
     "sourceId": 982,
     "sourceType": "datasetVersion"
    },
    {
     "datasetId": 715814,
     "sourceId": 1246668,
     "sourceType": "datasetVersion"
    },
    {
     "datasetId": 1173087,
     "sourceId": 2235542,
     "sourceType": "datasetVersion"
    }
   ],
   "dockerImageVersionId": 30055,
   "isGpuEnabled": false,
   "isInternetEnabled": false,
   "language": "python",
   "sourceType": "notebook"
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.9"
  },
  "papermill": {
   "default_parameters": {},
   "duration": 7.185168,
   "end_time": "2024-05-09T06:15:57.507924",
   "environment_variables": {},
   "exception": true,
   "input_path": "__notebook__.ipynb",
   "output_path": "__notebook__.ipynb",
   "parameters": {},
   "start_time": "2024-05-09T06:15:50.322756",
   "version": "2.2.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
